{- This file is part of funbot.
 -
 - Written in 2016, 2017 by fr33domlover <fr33domlover@riseup.net>.
 -
 - ♡ Copying is an act of love. Please copy, reuse and share.
 -
 - The author(s) have dedicated all copyright and related and neighboring
 - rights to this software to the public domain worldwide. This software is
 - distributed without any warranty.
 -
 - You should have received a copy of the CC0 Public Domain Dedication along
 - with this software. If not, see
 - <http://creativecommons.org/publicdomain/zero/1.0/>.
 -}

{-# LANGUAGE OverloadedStrings #-}

module FunBot.Settings.Sections.Locations
    ( locationOption
    , addLocation
    , removeLocation
    )
where

import Control.Monad (unless, void)
import Control.Monad.Trans.Class (lift)
import Data.Bool (bool)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.Sequence (Seq, (|>), (><), ViewL (..))
import Data.Settings.Section hiding (delete)
import Data.Settings.Types
import Database.Persist
import Network.IRC.Fun.Bot.IrcLog
import Network.IRC.Fun.Bot.MsgCount
import Network.IRC.Fun.Bot.Nicks
import Network.IRC.Fun.Bot.State
import Network.IRC.Fun.Types.Base (Channel (..), Nickname (..))

import qualified Data.CaseInsensitive as CI
import qualified Data.HashMap.Lazy as M
import qualified Data.Sequence as Q
import qualified Data.Text as T

import FunBot.Model
import FunBot.Settings.MkOption
import FunBot.Settings.Persist
import FunBot.Types
import FunBot.Util

locationOption l@(LocationLabel t) =
    let defl = "(?)"
        getl =
            maybe defl (unLocation . globalLocationContent . entityVal) <$>
            getBy (UniqueGlobalLocation l)
        setl v =
            void $
            upsert
                (GlobalLocation l $ LocationText v)
                [GlobalLocationContent =. LocationText v]
    in  (CI.original t, mkOptionP getl setl defl)

-- | Add a new location to settings and tree. Return whether success, i.e.
-- whether the location didn't exist and indeed a new one has been created.
addLocation :: LocationLabel -> LocationText -> BotSession Bool
addLocation label location = do
    mlid <- runDB $ insertUnique $ GlobalLocation label location
    case mlid of
        Nothing -> return False
        Just _  -> do
            let (t, opt) = locationOption label
                ins = insertOpt ["locations", t] opt
            modifyState $ \ s -> s { bsSTree = ins $ bsSTree s }
            return True

-- | Remove a location from settings and tree. Return whether success, i.e.
-- whether the location did exist and indeed has been deleted.
removeLocation :: LocationLabel -> BotSession Bool
removeLocation label = runDB $ do
    mel <- getBy $ UniqueGlobalLocation label
    case mel of
        Nothing              -> return False
        Just (Entity lid _l) -> do
            delete lid
            let path = ["locations", CI.original $ unLocationLabel label]
                del = deleteOpt path
            lift $ modifyState $ \ s -> s { bsSTree = del $ bsSTree s }
            return True
